#target photoshop

app.bringToFront();

var doc = app.activeDocument;
var allLayersInfo = [];
var exportSettings = {
    destination: "",
    fileFormat: "PNG",
    quality: 8,
    exportMetadata: true,
    exportTextMd: true,
    trim: true
};

function LayerInfo(layer, parentPath) {
    this.layer = layer;
    this.id = layer.id;
    this.name = layer.name;
    this.type = layer.typename === "ArtLayer" ? (layer.kind === LayerKind.TEXT ? "text" : "layer") : "group";
    this.visible = layer.visible;
    this.parentPath = parentPath ? parentPath.slice() : [];
    this.fullPath = this.parentPath.length > 0 ? this.parentPath.join("/") + "/" + this.name : this.name;
    this.selected = true;
    this.bounds = null;
    
    try {
        this.bounds = layer.bounds;
    } catch (e) {}
    
    this.textInfo = null;
    if (this.type === "text") {
        this.textInfo = this.collectTextInfo(layer);
    }
}

LayerInfo.prototype.collectTextInfo = function(layer) {
    var info = {
        content: "",
        fontSize: 0,
        fontFamily: "",
        color: "",
        colorHex: "",
        hasStroke: false,
        strokeSize: 0,
        strokeColor: "",
        strokeColorHex: ""
    };
    
    try {
        var textItem = layer.textItem;
        info.content = textItem.contents || "";
        info.fontSize = Math.round(textItem.size) || 0;
        info.fontFamily = textItem.font || "";
        
        if (textItem.color && textItem.color.rgb) {
            var r = Math.round(textItem.color.rgb.red);
            var g = Math.round(textItem.color.rgb.green);
            var b = Math.round(textItem.color.rgb.blue);
            info.color = "rgb(" + r + "," + g + "," + b + ")";
            info.colorHex = rgbToHex(r, g, b);
        }
        
        try {
            var ref = new ActionReference();
            ref.putIdentifier(charIDToTypeID("Lyr "), layer.id);
            var layerDesc = executeActionGet(ref);
            
            if (layerDesc.hasKey(stringIDToTypeID("layerEffects"))) {
                var effects = layerDesc.getObjectValue(stringIDToTypeID("layerEffects"));
                
                if (effects.hasKey(stringIDToTypeID("frameFX"))) {
                    var strokeDesc = effects.getObjectValue(stringIDToTypeID("frameFX"));
                    
                    if (strokeDesc.hasKey(stringIDToTypeID("enabled"))) {
                        info.hasStroke = strokeDesc.getBoolean(stringIDToTypeID("enabled"));
                        
                        if (info.hasStroke) {
                            if (strokeDesc.hasKey(stringIDToTypeID("size"))) {
                                info.strokeSize = strokeDesc.getUnitDoubleValue(stringIDToTypeID("size"));
                            }
                            
                            if (strokeDesc.hasKey(stringIDToTypeID("color"))) {
                                var colorDesc = strokeDesc.getObjectValue(stringIDToTypeID("color"));
                                if (colorDesc.hasKey(stringIDToTypeID("red"))) {
                                    var sr = Math.round(colorDesc.getDouble(stringIDToTypeID("red")));
                                    var sg = Math.round(colorDesc.getDouble(stringIDToTypeID("green")));
                                    var sb = Math.round(colorDesc.getDouble(stringIDToTypeID("blue")));
                                    info.strokeColor = "rgb(" + sr + "," + sg + "," + sb + ")";
                                    info.strokeColorHex = rgbToHex(sr, sg, sb);
                                }
                            }
                        }
                    }
                }
            }
        } catch (e) {}
    } catch (e) {}
    
    return info;
};

LayerInfo.prototype.getDisplayText = function() {
    if (!this.textInfo) return "";
    
    var text = this.textInfo.content.substring(0, 15);
    if (this.textInfo.content.length > 15) text += "...";
    
    var parts = [text];
    if (this.textInfo.fontFamily) parts.push(this.textInfo.fontFamily);
    if (this.textInfo.fontSize > 0) parts.push(this.textInfo.fontSize + "px");
    if (this.textInfo.colorHex) parts.push(this.textInfo.colorHex);
    if (this.textInfo.hasStroke) parts.push("\u63CF\u8FB9:" + Math.round(this.textInfo.strokeSize) + "px");
    
    return parts.join(" | ");
};

function rgbToHex(r, g, b) {
    var toHex = function(n) {
        var hex = Math.round(n).toString(16);
        return hex.length === 1 ? "0" + hex : hex;
    };
    return "#" + toHex(r) + toHex(g) + toHex(b);
}

function collectAllLayers(parent, parentPath) {
    var layers = parent.layers || parent.artLayers;
    
    for (var i = layers.length - 1; i >= 0; i--) {
        try {
            var layer = layers[i];
            var layerInfo = new LayerInfo(layer, parentPath);
            allLayersInfo.push(layerInfo);
            
            if (layerInfo.type === "group") {
                var newPath = parentPath ? parentPath.slice() : [];
                newPath.push(layer.name);
                collectAllLayers(layer, newPath);
            }
        } catch (e) {}
    }
}

function createFilterDialog() {
    var dialog = new Window("dialog", "\u9009\u62E9\u8981\u5BFC\u51FA\u7684\u56FE\u5C42");
    dialog.alignChildren = ["fill", "top"];
    dialog.spacing = 10;
    dialog.margins = 16;
    dialog.preferredSize = [1000, 600];
    
    var searchGroup = dialog.add("group");
    searchGroup.orientation = "row";
    searchGroup.alignChildren = ["left", "center"];
    searchGroup.add("statictext", undefined, "\u641C\u7D22:");
    var searchInput = searchGroup.add("edittext", undefined, "");
    searchInput.characters = 30;
    searchInput.helpTip = "\u641C\u7D22\u56FE\u5C42\u540D\u79F0\u3001\u8DEF\u5F84\u6216\u6587\u5B57\u5185\u5BB9";
    var cbSearchSelect = searchGroup.add("checkbox", undefined, "\u9009\u4E2D\u641C\u7D22\u7ED3\u679C");
    cbSearchSelect.helpTip = "\u52FE\u9009:\u9009\u4E2D\u641C\u7D22\u7ED3\u679C | \u53D6\u6D88:\u53D6\u6D88\u9009\u4E2D\u641C\u7D22\u7ED3\u679C";
    cbSearchSelect.enabled = false;
    
    var filterGroup = dialog.add("group");
    filterGroup.orientation = "row";
    filterGroup.alignChildren = ["left", "center"];
    var cbShowText = filterGroup.add("checkbox", undefined, "\u6587\u5B57\u56FE\u5C42");
    cbShowText.value = true;
    var cbShowLayers = filterGroup.add("checkbox", undefined, "\u666E\u901A\u56FE\u5C42");
    cbShowLayers.value = true;
    var cbShowGroups = filterGroup.add("checkbox", undefined, "\u7EC4/\u6587\u4EF6\u5939");
    cbShowGroups.value = true;
    var cbShowInvisible = filterGroup.add("checkbox", undefined, "\u9690\u85CF\u56FE\u5C42");
    cbShowInvisible.value = true;
    
    var statsGroup = dialog.add("group");
    statsGroup.orientation = "row";
    statsGroup.alignChildren = ["left", "center"];
    var statsText = statsGroup.add("statictext", undefined, "\u603B\u8BA1: 0 | \u5DF2\u9009: 0");
    statsText.graphics.font = ScriptUI.newFont(statsText.graphics.font.name, ScriptUI.FontStyle.BOLD, 12);
    
    var listPanel = dialog.add("panel", undefined, "\u56FE\u5C42\u5217\u8868 (\u70B9\u51FB\u9009\u62E9/\u53D6\u6D88\u9009\u62E9)");
    listPanel.alignChildren = ["fill", "fill"];
    listPanel.margins = 10;
    
    var listBox = listPanel.add("listbox", undefined, [], {
        numberOfColumns: 5,
        showHeaders: true,
        columnTitles: ["\u2611", "\u540D\u79F0", "\u7C7B\u578B", "\u8DEF\u5F84", "\u4FE1\u606F"],
        columnWidths: [40, 180, 60, 250, 300]
    });
    listBox.preferredSize.height = 350;
    
    var btnGroup1 = dialog.add("group");
    btnGroup1.orientation = "row";
    btnGroup1.alignChildren = ["center", "center"];
    var btnSelectAll = btnGroup1.add("button", undefined, "\u5168\u9009");
    var btnDeselectAll = btnGroup1.add("button", undefined, "\u53D6\u6D88\u5168\u9009");
    var btnInvertSelection = btnGroup1.add("button", undefined, "\u53CD\u9009");
    var btnSelectVisible = btnGroup1.add("button", undefined, "\u53EA\u9009\u53EF\u89C1");
    var btnSelectText = btnGroup1.add("button", undefined, "\u53EA\u9009\u6587\u5B57");
    
    var settingsPanel = dialog.add("panel", undefined, "\u5BFC\u51FA\u8BBE\u7F6E");
    settingsPanel.alignChildren = ["fill", "top"];
    settingsPanel.orientation = "column";
    
    var destGroup = settingsPanel.add("group");
    destGroup.orientation = "row";
    destGroup.alignChildren = ["left", "center"];
    destGroup.add("statictext", undefined, "\u5BFC\u51FA\u76EE\u5F55:");
    var destInput = destGroup.add("edittext", undefined, "");
    destInput.characters = 30;
    var btnBrowse = destGroup.add("button", undefined, "\u6D4F\u89C8...");
    
    var optionsGroup = settingsPanel.add("group");
    optionsGroup.orientation = "row";
    optionsGroup.alignChildren = ["left", "center"];
    var cbTrim = optionsGroup.add("checkbox", undefined, "\u88C1\u526A\u900F\u660E\u533A\u57DF");
    cbTrim.value = true;
    var cbMetadata = optionsGroup.add("checkbox", undefined, "\u5BFC\u51FAJSON\u5143\u6570\u636E");
    cbMetadata.value = true;
    var cbTextMd = optionsGroup.add("checkbox", undefined, "\u5BFC\u51FAMD\u6587\u4EF6");
    cbTextMd.value = true;
    
    var btnGroup2 = dialog.add("group");
    btnGroup2.orientation = "row";
    btnGroup2.alignChildren = ["center", "center"];
    btnGroup2.spacing = 10;
    var btnExport = btnGroup2.add("button", undefined, "\u5F00\u59CB\u5BFC\u51FA", {name: "ok"});
    btnExport.preferredSize.width = 120;
    var btnCancel = btnGroup2.add("button", undefined, "\u53D6\u6D88", {name: "cancel"});
    btnCancel.preferredSize.width = 120;
    
    function updateList(filterText) {
        listBox.removeAll();
        var filter = (filterText || "").toLowerCase();
        var totalCount = 0;
        var selectedCount = 0;
        
        cbSearchSelect.enabled = filter.length > 0;
        if (filter.length === 0) {
            cbSearchSelect.value = false;
        }
        
        for (var i = 0; i < allLayersInfo.length; i++) {
            var info = allLayersInfo[i];
            
            if (!cbShowText.value && info.type === "text") continue;
            if (!cbShowLayers.value && info.type === "layer") continue;
            if (!cbShowGroups.value && info.type === "group") continue;
            if (!cbShowInvisible.value && !info.visible) continue;
            
            if (filter.length > 0) {
                var matchName = info.name.toLowerCase().indexOf(filter) >= 0;
                var matchPath = info.fullPath.toLowerCase().indexOf(filter) >= 0;
                var matchText = info.textInfo && info.textInfo.content.toLowerCase().indexOf(filter) >= 0;
                if (!matchName && !matchPath && !matchText) continue;
            }
            
            totalCount++;
            if (info.selected) selectedCount++;
            
            var typeText = info.type === "text" ? "\u6587\u5B57" : (info.type === "group" ? "\u7EC4" : "\u56FE\u5C42");
            var displayInfo = info.getDisplayText();
            
            var item = listBox.add("item", info.selected ? "\u2611" : "\u2610");
            item.subItems[0].text = info.name;
            item.subItems[1].text = typeText;
            item.subItems[2].text = info.fullPath;
            item.subItems[3].text = displayInfo;
            
            item.layerIndex = i;
        }
        
        statsText.text = "\u603B\u8BA1: " + totalCount + " | \u5DF2\u9009: " + selectedCount;
    }
    
    searchInput.onChanging = function() {
        updateList(this.text);
    };
    
    cbShowText.onClick = function() { updateList(searchInput.text); };
    cbShowLayers.onClick = function() { updateList(searchInput.text); };
    cbShowGroups.onClick = function() { updateList(searchInput.text); };
    cbShowInvisible.onClick = function() { updateList(searchInput.text); };
    
    cbSearchSelect.onClick = function() {
        var filter = searchInput.text.toLowerCase();
        if (filter.length === 0) return;
        
        var shouldSelect = this.value;
        
        for (var i = 0; i < allLayersInfo.length; i++) {
            var info = allLayersInfo[i];
            
            if (!cbShowText.value && info.type === "text") continue;
            if (!cbShowLayers.value && info.type === "layer") continue;
            if (!cbShowGroups.value && info.type === "group") continue;
            if (!cbShowInvisible.value && !info.visible) continue;
            
            var matchName = info.name.toLowerCase().indexOf(filter) >= 0;
            var matchPath = info.fullPath.toLowerCase().indexOf(filter) >= 0;
            var matchText = info.textInfo && info.textInfo.content.toLowerCase().indexOf(filter) >= 0;
            
            if (matchName || matchPath || matchText) {
                allLayersInfo[i].selected = shouldSelect;
            }
        }
        
        updateList(searchInput.text);
    };
    
    listBox.onChange = function() {
        if (this.selection) {
            var layerIndex = this.selection.layerIndex;
            allLayersInfo[layerIndex].selected = !allLayersInfo[layerIndex].selected;
            this.selection.text = allLayersInfo[layerIndex].selected ? "\u2611" : "\u2610";
            updateList(searchInput.text);
        }
    };
    
    btnSelectAll.onClick = function() {
        for (var i = 0; i < allLayersInfo.length; i++) {
            allLayersInfo[i].selected = true;
        }
        updateList(searchInput.text);
    };
    
    btnDeselectAll.onClick = function() {
        for (var i = 0; i < allLayersInfo.length; i++) {
            allLayersInfo[i].selected = false;
        }
        updateList(searchInput.text);
    };
    
    btnInvertSelection.onClick = function() {
        for (var i = 0; i < allLayersInfo.length; i++) {
            allLayersInfo[i].selected = !allLayersInfo[i].selected;
        }
        updateList(searchInput.text);
    };
    
    btnSelectVisible.onClick = function() {
        for (var i = 0; i < allLayersInfo.length; i++) {
            allLayersInfo[i].selected = allLayersInfo[i].visible;
        }
        updateList(searchInput.text);
    };
    
    btnSelectText.onClick = function() {
        for (var i = 0; i < allLayersInfo.length; i++) {
            allLayersInfo[i].selected = (allLayersInfo[i].type === "text");
        }
        updateList(searchInput.text);
    };
    
    btnBrowse.onClick = function() {
        var folder = Folder.selectDialog("\u9009\u62E9\u5BFC\u51FA\u76EE\u5F55");
        if (folder) {
            destInput.text = folder.fsName;
        }
    };
    
    updateList("");
    
    if (dialog.show() === 1) {
        exportSettings.destination = destInput.text;
        exportSettings.trim = cbTrim.value;
        exportSettings.exportMetadata = cbMetadata.value;
        exportSettings.exportTextMd = cbTextMd.value;
        
        if (!exportSettings.destination) {
            alert("\u8BF7\u9009\u62E9\u5BFC\u51FA\u76EE\u5F55");
            return false;
        }
        
        return true;
    }
    
    return false;
}

function getSelectedLayers() {
    var selected = [];
    for (var i = 0; i < allLayersInfo.length; i++) {
        if (allLayersInfo[i].selected) {
            selected.push(allLayersInfo[i]);
        }
    }
    return selected;
}

function exportSelectedLayers() {
    var selectedLayers = getSelectedLayers();
    
    if (selectedLayers.length === 0) {
        alert("\u6CA1\u6709\u9009\u62E9\u4EFB\u4F55\u56FE\u5C42");
        return;
    }
    
    var progressWin = new Window("palette", "\u5BFC\u51FA\u8FDB\u5EA6");
    progressWin.add("statictext", undefined, "\u6B63\u5728\u5BFC\u51FA\u56FE\u5C42...");
    var progressBar = progressWin.add("progressbar", undefined, 0, selectedLayers.length);
    progressBar.preferredSize = [300, 20];
    var progressText = progressWin.add("statictext", undefined, "0 / " + selectedLayers.length);
    progressWin.show();
    
    var exported = 0;
    var errors = [];
    
    for (var i = 0; i < selectedLayers.length; i++) {
        try {
            var layerInfo = selectedLayers[i];
            progressText.text = (i + 1) + " / " + selectedLayers.length + " - " + layerInfo.name;
            progressBar.value = i + 1;
            progressWin.update();
            
            exportSingleLayer(layerInfo);
            exported++;
        } catch (e) {
            errors.push(layerInfo.name + ": " + e.toString());
        }
    }
    
    progressWin.close();
    
    var message = "\u5BFC\u51FA\u5B8C\u6210!\n\n";
    message += "\u6210\u529F: " + exported + "\n";
    if (errors.length > 0) {
        message += "\u5931\u8D25: " + errors.length + "\n\n";
        message += "\u9519\u8BEF\u4FE1\u606F:\n" + errors.slice(0, 5).join("\n");
        if (errors.length > 5) {
            message += "\n...\u548C\u5176\u4ED6 " + (errors.length - 5) + " \u4E2A\u9519\u8BEF";
        }
    }
    
    alert(message);
}

function trimDocumentSilent() {
    var idtrim = stringIDToTypeID("trim");
    var desc = new ActionDescriptor();
    desc.putEnumerated(stringIDToTypeID("trimBasedOn"), stringIDToTypeID("trimBasedOn"), stringIDToTypeID("transparency"));
    desc.putBoolean(charIDToTypeID("Top "), true);
    desc.putBoolean(charIDToTypeID("Btom"), true);
    desc.putBoolean(charIDToTypeID("Left"), true);
    desc.putBoolean(charIDToTypeID("Rght"), true);
    executeAction(idtrim, desc, DialogModes.NO);
}

function isClippingLayer(layer) {
    try {
        return layer && layer.typename === "ArtLayer" && layer.grouped;
    } catch (e) {
        return false;
    }
}

function selectLayerBelow() {
    var result = null;
    try {
        var idslct = charIDToTypeID("slct");
        var desc = new ActionDescriptor();
        var ref = new ActionReference();
        ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Bckw"));
        desc.putReference(charIDToTypeID("null"), ref);
        desc.putBoolean(charIDToTypeID("MkVs"), false);
        executeAction(idslct, desc, DialogModes.NO);
        result = doc.activeLayer;
    } catch (e) {
        result = null;
    }
    return result;
}

function selectLayerAbove() {
    var result = null;
    try {
        var idslct = charIDToTypeID("slct");
        var desc = new ActionDescriptor();
        var ref = new ActionReference();
        ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Frwr"));
        desc.putReference(charIDToTypeID("null"), ref);
        desc.putBoolean(charIDToTypeID("MkVs"), false);
        executeAction(idslct, desc, DialogModes.NO);
        result = doc.activeLayer;
    } catch (e) {
        result = null;
    }
    return result;
}

function mergeClippingChainForExport(layer) {
    if (!layer) return null;
    try {
        doc.activeLayer = layer;
        var chain = [];
        chain.push(layer);
        var topLayer = layer;
        
        while (true) {
            var above = selectLayerAbove();
            if (!above || !above.grouped) {
                break;
            }
            topLayer = above;
            chain.unshift(above);
        }
        
        doc.activeLayer = layer;
        while (true) {
            var below = selectLayerBelow();
            if (!below) {
                break;
            }
            chain.push(below);
            if (!below.grouped) {
                break;
            }
        }
        
        var savedStates = [];
        for (var i = 0; i < chain.length; i++) {
            var item = chain[i];
            var state = true;
            try { state = item.visible; } catch (stateErr) {}
            savedStates.push({ layer: item, visible: state });
            try { item.visible = true; } catch (setErr) {}
        }
 
        // Ensure the canvas includes the clipping chain bounds (to avoid empty selection errors)
        try {
            var unionLeft = null, unionTop = null, unionRight = null, unionBottom = null;
            for (var b = 0; b < chain.length; b++) {
                try {
                    var cb = chain[b].bounds;
                    if (cb && cb.length >= 4) {
                        var l = cb[0].value, t = cb[1].value, r = cb[2].value, bt = cb[3].value;
                        if (unionLeft === null || l < unionLeft) unionLeft = l;
                        if (unionTop === null || t < unionTop) unionTop = t;
                        if (unionRight === null || r > unionRight) unionRight = r;
                        if (unionBottom === null || bt > unionBottom) unionBottom = bt;
                    }
                } catch (ignoreBoundsErr) {}
            }
            if (unionLeft !== null && unionTop !== null && unionRight !== null && unionBottom !== null) {
                var canvasWidth = doc.width.value;
                var canvasHeight = doc.height.value;
                var expandLeft = Math.max(0, -unionLeft);
                var expandTop = Math.max(0, -unionTop);
                var expandRight = Math.max(0, unionRight - canvasWidth);
                var expandBottom = Math.max(0, unionBottom - canvasHeight);
                if (expandLeft > 0 || expandTop > 0 || expandRight > 0 || expandBottom > 0) {
                    var newWidth = canvasWidth + expandLeft + expandRight;
                    var newHeight = canvasHeight + expandTop + expandBottom;
                    var anchorPos = AnchorPosition.MIDDLECENTER;
                    if (expandLeft > 0 && expandTop > 0) {
                        anchorPos = AnchorPosition.BOTTOMRIGHT;
                    } else if (expandLeft > 0 && expandBottom > 0) {
                        anchorPos = AnchorPosition.TOPRIGHT;
                    } else if (expandRight > 0 && expandTop > 0) {
                        anchorPos = AnchorPosition.BOTTOMLEFT;
                    } else if (expandRight > 0 && expandBottom > 0) {
                        anchorPos = AnchorPosition.TOPLEFT;
                    } else if (expandLeft > 0) {
                        anchorPos = AnchorPosition.MIDDLERIGHT;
                    } else if (expandRight > 0) {
                        anchorPos = AnchorPosition.MIDDLELEFT;
                    } else if (expandTop > 0) {
                        anchorPos = AnchorPosition.BOTTOMCENTER;
                    } else if (expandBottom > 0) {
                        anchorPos = AnchorPosition.TOPCENTER;
                    }
                    doc.resizeCanvas(
                        new UnitValue(newWidth, doc.width.type),
                        new UnitValue(newHeight, doc.height.type),
                        anchorPos
                    );
                }
            }
        } catch (expandErr) {}

        try {
            var prevDialogs = null;
            try { prevDialogs = app.displayDialogs; } catch (dlgErr) {}
            try { app.displayDialogs = DialogModes.NO; } catch (dlgSetErr) {}
            doc.selection.selectAll();
            doc.selection.copy(true);
            doc.selection.deselect();
            var mergedLayer = doc.paste();
            try { app.displayDialogs = prevDialogs; } catch (dlgRestoreErr) {}
            
            for (var m = 0; m < savedStates.length; m++) {
                try { savedStates[m].layer.visible = savedStates[m].visible; } catch (restoreErr) {}
            }
            
            doc.activeLayer = mergedLayer;
            return mergedLayer;
        } catch (selErr) {
            try { app.displayDialogs = prevDialogs; } catch (dlgRestoreErr2) {}
            for (var m = 0; m < savedStates.length; m++) {
                try { savedStates[m].layer.visible = savedStates[m].visible; } catch (restoreErr) {}
            }
            return layer;
        }
    } catch (e) {
        return layer;
    }
}

function exportSingleLayer(layerInfo) {
    var originalState = doc.activeHistoryState;
    
    try {
        hideAllLayers(doc);
        
        var layer = layerInfo.layer;
        var exportLayer = layer;
        
        if (layer.typename === "LayerSet") {
            showLayer(layer);
        } else {
            showLayer(layer);
            
            try {
                doc.activeLayer = layer;
                
                if (isClippingLayer(layer)) {
                    var mergedLayer = mergeClippingChainForExport(layer);
                    if (mergedLayer && mergedLayer !== layer) {
                        exportLayer = mergedLayer;
                        try {
                            doc.activeLayer = exportLayer;
                        } catch (e) {}
                    }
                } else {
                    exportLayer = doc.activeLayer;
                }
            } catch (prepErr) {}
        }
        
        var exportBounds = null;
        try {
            exportBounds = exportLayer.bounds;
        } catch (boundsErr) {
            try {
                exportBounds = layer.bounds;
            } catch (e) {}
        }
        
        var skipForEmpty = false;
        if (exportBounds) {
            skipForEmpty = !(exportBounds[0] < exportBounds[2] && exportBounds[1] < exportBounds[3]);
        }
        
        if (skipForEmpty) {
            return;
        }
        
        var filePath = makeFilePath(layerInfo);
        
        if (!ensureFolderExists(filePath)) {
            throw new Error("\u65E0\u6CD5\u521B\u5EFA\u76EE\u5F55: " + filePath);
        }
        
        // Ensure content outside canvas is included before trimming
        try {
            if (exportBounds) {
                var canvasWidth = doc.width.value;
                var canvasHeight = doc.height.value;
                var left = exportBounds[0].value;
                var top = exportBounds[1].value;
                var right = exportBounds[2].value;
                var bottom = exportBounds[3].value;

                if (left < 0 || top < 0 || right > canvasWidth || bottom > canvasHeight) {
                    var expandLeft = Math.max(0, -left);
                    var expandTop = Math.max(0, -top);
                    var expandRight = Math.max(0, right - canvasWidth);
                    var expandBottom = Math.max(0, bottom - canvasHeight);

                    var newWidth = canvasWidth + expandLeft + expandRight;
                    var newHeight = canvasHeight + expandTop + expandBottom;

                    var anchorPos = AnchorPosition.MIDDLECENTER;
                    if (expandLeft > 0 && expandTop > 0) {
                        anchorPos = AnchorPosition.BOTTOMRIGHT;
                    } else if (expandLeft > 0 && expandBottom > 0) {
                        anchorPos = AnchorPosition.TOPRIGHT;
                    } else if (expandRight > 0 && expandTop > 0) {
                        anchorPos = AnchorPosition.BOTTOMLEFT;
                    } else if (expandRight > 0 && expandBottom > 0) {
                        anchorPos = AnchorPosition.TOPLEFT;
                    } else if (expandLeft > 0) {
                        anchorPos = AnchorPosition.MIDDLERIGHT;
                    } else if (expandRight > 0) {
                        anchorPos = AnchorPosition.MIDDLELEFT;
                    } else if (expandTop > 0) {
                        anchorPos = AnchorPosition.BOTTOMCENTER;
                    } else if (expandBottom > 0) {
                        anchorPos = AnchorPosition.TOPCENTER;
                    }

                    doc.resizeCanvas(
                        new UnitValue(newWidth, doc.width.type),
                        new UnitValue(newHeight, doc.height.type),
                        anchorPos
                    );
                }
            }
        } catch (expandErr) {}

        trimDocumentSilent();
        
        var saveFile = new File(filePath);
        var pngOptions = new PNGSaveOptions();
        pngOptions.compression = 9;
        pngOptions.interlaced = false;
        
        doc.saveAs(saveFile, pngOptions, true, Extension.LOWERCASE);
        
        if (exportSettings.exportTextMd && layerInfo.textInfo) {
            saveTextMd(layerInfo, filePath);
        }
    } finally {
        doc.activeHistoryState = originalState;
    }
}

function hideAllLayers(parent) {
    var layers = parent.layers || parent.artLayers;
    for (var i = 0; i < layers.length; i++) {
        try {
            layers[i].visible = false;
            if (layers[i].typename === "LayerSet") {
                hideAllLayers(layers[i]);
            }
        } catch (e) {}
    }
}

function showLayer(layer) {
    try {
        layer.visible = true;
        
        if (layer.typename === "LayerSet") {
            showAllChildLayers(layer);
        }
        
        var parent = layer.parent;
        while (parent && parent.typename !== "Document") {
            parent.visible = true;
            parent = parent.parent;
        }
    } catch (e) {}
}

function showAllChildLayers(group) {
    try {
        var layers = group.layers;
        for (var i = 0; i < layers.length; i++) {
            try {
                layers[i].visible = true;
                if (layers[i].typename === "LayerSet") {
                    showAllChildLayers(layers[i]);
                }
            } catch (e) {}
        }
    } catch (e) {}
}

function makeFileName(layerInfo) {
    var name = layerInfo.name;
    name = name.replace(/[\\\/\:\*\?\"\<\>\|]/g, "-");
    
    return name;
}

function makeFilePath(layerInfo) {
    var path = exportSettings.destination;
    
    if (layerInfo.parentPath.length > 0) {
        for (var i = 0; i < layerInfo.parentPath.length; i++) {
            var folderName = layerInfo.parentPath[i].replace(/[\\\/\:\*\?\"\<\>\|]/g, "-");
            path += "/" + folderName;
        }
    }
    
    var fileName = makeFileName(layerInfo);
    path += "/" + fileName + ".png";
    
    return path;
}

function ensureFolderExists(filePath) {
    try {
        var file = new File(filePath);
        var folder = file.parent;
        
        if (!folder.exists) {
            folder.create();
        }
        
        return true;
    } catch (e) {
        return false;
    }
}

function saveTextMd(layerInfo, imagePath) {
    try {
        var text = layerInfo.textInfo;
        if (!text) return;
        
        var mdContent = "";
        
        mdContent += "## \u5B57\u4F53\u5C5E\u6027\n\n";
        mdContent += "- **\u5B57\u4F53**: " + text.fontFamily + "\n";
        mdContent += "- **\u5927\u5C0F**: " + text.fontSize + "px\n";
        mdContent += "- **\u5B57\u53F7**: " + text.fontSize + "\n";
        
        mdContent += "\n## \u989C\u8272\n\n";
        mdContent += "- **RGB**: " + text.color + "\n";
        mdContent += "- **HEX**: " + text.colorHex + "\n";
        
        if (text.hasStroke) {
            mdContent += "\n## \u63CF\u8FB9\n\n";
            mdContent += "- **\u5927\u5C0F**: " + Math.round(text.strokeSize) + "px\n";
            mdContent += "- **\u989C\u8272 RGB**: " + text.strokeColor + "\n";
            mdContent += "- **\u989C\u8272 HEX**: " + text.strokeColorHex + "\n";
        }
        
        mdContent += "\n## \u6587\u5B57\u5185\u5BB9\n\n";
        mdContent += text.content + "\n";
        
        var mdPath = imagePath.substring(0, imagePath.lastIndexOf(".")) + ".md";
        var mdFile = new File(mdPath);
        mdFile.encoding = "UTF8";
        mdFile.open("w");
        mdFile.write(mdContent);
        mdFile.close();
    } catch (e) {}
}

function main() {
    if (!doc) {
        alert("\u8BF7\u5148\u6253\u5F00\u4E00\u4E2A\u6587\u6863");
        return;
    }
    
    collectAllLayers(doc, null);
    
    if (allLayersInfo.length === 0) {
        alert("\u6CA1\u6709\u627E\u5230\u4EFB\u4F55\u56FE\u5C42");
        return;
    }
    
    if (createFilterDialog()) {
        exportSelectedLayers();
    }
}

main();

